// Copyright 2022 jeff.li. and/or its affiliates.

#pragma once

#include <tbir/runtime/ft_container.h>

namespace tbir::runtime {

    namespace Kernel_FTList {
        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make() {
            return FTList<T>();
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(std::initializer_list<T> init_args) {
            return FTList<T>(init_args);
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const FTList <T> &c) {
            return FTList<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const FTSet <T> &c) {
            return FTList<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const List &c) {
            return FTList<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const Set &c) {
            return FTList<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const Iterator &itr) {
            FTList<T> d;
            bool has_next = itr.HasNext();
            while (has_next) {
                d.push_back(itr.Next(&has_next));
            }
            return d;
        }

        template<typename T>
        TURBO_FORCE_INLINE FTList <T> make(const RTValue &c) {
            switch (c.type_code()) {
                case TypeIndex::kRuntimeList: {
                    return make<T>(c.AsObjectViewNoCheck<List>().data());
                }
                    break;
                case TypeIndex::kRuntimeSet: {
                    return make<T>(c.AsObjectViewNoCheck<Set>().data());
                }
                    break;
                case TypeIndex::kRuntimeIterator: {
                    return make<T>(c.AsObjectViewNoCheck<Iterator>().data());
                }
                    break;
                default: {
                    return make<T>(Kernel_Iterable::make(c));
                }
                    break;
            }
        }
    }  // namespace Kernel_FTList

    namespace Kernel_FTSet {
        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make() {
            return FTSet<T>();
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(std::initializer_list<T> init_args) {
            return FTSet<T>(init_args);
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const FTSet <T> &c) {
            return FTSet<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const FTList <T> &c) {
            return FTSet<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const List &c) {
            return FTSet<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const Set &c) {
            return FTSet<T>(c.begin(), c.end());
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const Iterator &itr) {
            FTSet<T> d;
            bool has_next = itr.HasNext();
            while (has_next) {
                d.emplace(itr.Next(&has_next));
            }
            return d;
        }

        template<typename T>
        TURBO_FORCE_INLINE FTSet <T> make(const RTValue &c) {
            switch (c.type_code()) {
                case TypeIndex::kRuntimeSet: {
                    return make<T>(c.AsObjectViewNoCheck<Set>().data());
                }
                    break;
                case TypeIndex::kRuntimeList: {
                    return make<T>(c.AsObjectViewNoCheck<List>().data());
                }
                    break;
                default: {
                    return make<T>(Kernel_Iterable::make(c));
                }
                    break;
            }
        }
    }  // namespace Kernel_FTSet

    namespace Kernel_FTDict {
        template<typename K, typename V>
        TURBO_FORCE_INLINE FTDict <K, V> make() {
            return FTDict<K, V>{};
        }

        template<typename K, typename V>
        TURBO_FORCE_INLINE FTDict <K, V> make(
                std::initializer_list<typename FTDict<K, V>::value_type> init_args) {
            return FTDict<K, V>(init_args);
        }

        template<typename K, typename V>
        TURBO_FORCE_INLINE FTDict <K, V> make(const FTDict <K, V> &c) {
            FTDict<K, V> r;
            r.reserve(c.size());
            for (auto &value_type : c.items()) {
                r.emplace(value_type.first, value_type.second);
            }
            return r;
        }

        template<typename K, typename V>
        TURBO_FORCE_INLINE FTDict <K, V> make(const Dict &c) {
            FTDict<K, V> r;
            r.reserve(c.size());
            for (auto &value_type : c.items()) {
                r.emplace(value_type.first, value_type.second);
            }
            return r;
        }

        template<typename K, typename V>
        TURBO_FORCE_INLINE FTDict <K, V> make(const RTValue &c) {
            switch (c.type_code()) {
                case TypeIndex::kRuntimeDict: {
                    return make<K, V>(c.AsObjectViewNoCheck<Dict>().data());
                }
                    break;
                default: {
                    MXTHROW << "TypeError: dict(...) not support '" << c.type_name() << "'";
                    return {};
                }
                    break;
            }
        }
    }  // namespace Kernel_FTDict

}  // namespace tbir::runtime
